package com.gitee.liuzhi.design.structure;

/**
 * @Author liuzhi
 * @Date 2023/8/27 17:04
 * @Version 1.0
 * @Description 桥接模式 Bridge Pattern
 * <p>
 * 桥接模式将抽象与实现解耦, 使二者可以独立变化
 * <p>
 * 关键代码
 * 1. 定义抽象地依赖项, 而具体地实现由方法的参数动态传入从而解耦
 * <p>
 * 使用场景
 * 1. 当一个类存在两个独立变化的维度, 且这两个维度都需要进行扩展时
 * 2. 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时
 * 3. 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时
 * 例如 : 支付有微信和支付宝, 支付方式有人脸、扫码和密码
 * 例如 : 女士皮包有很多种, 可以按用途分、按皮质分、按品牌分、按颜色分、按大小分等, 存在多个维度的变化, 所以采用桥接模式来实现女士皮包的选购比较合适
 * 为了避免组合的实现方式产生笛卡尔积, 所以选择桥接模式
 */
public class BridgePattern {

    /*
    一个甜品店, 售卖的食品有蛋糕、奶茶和牛奶, 但是每个商品都有各种口味: 草莓味、芒果味、香蕉味
    创建两个父类, 一个食品类一个水果类, 两个父类各自包含了相应的子类, 然后根据需要将食品和水果进行组合
     */
    public static void main(String[] args) {
        // 蛋糕
        Food cake = new Cake();
        cake.setFruit(new Mango());
        cake.add();
        // 牛奶
        Food milk = new Milk();
        milk.setFruit(new Strawberry());
        milk.add();
    }

    public interface Fruit {
        /**
         * 被添加
         *
         * @param food foodName
         */
        void beAdd(String food);
    }

    public static class Banana implements Fruit {
        @Override
        public void beAdd(String food) {
            System.out.println("香蕉" + food);
        }
    }

    public static class Strawberry implements Fruit {
        @Override
        public void beAdd(String food) {
            System.out.println("草莓" + food);
        }
    }

    public static class Mango implements Fruit {
        @Override
        public void beAdd(String food) {
            System.out.println("芒果" + food);
        }
    }


    public abstract static class Food {

        Fruit fruit;

        public void setFruit(Fruit fruit) {
            this.fruit = fruit;
        }

        /**
         * 制作时添加
         */
        public abstract void add();
    }

    public static class Cake extends Food {

        @Override
        public void add() {
            fruit.beAdd("蛋糕");
        }
    }

    public static class Milk extends Food {
        @Override
        public void add() {
            fruit.beAdd("牛奶");
        }
    }

    public static class MilkTea extends Food {
        @Override
        public void add() {
            fruit.beAdd("奶茶");
        }
    }

    /*
    汽车品牌: 奔驰和宝马
    汽车音响: 柏林之声和哈曼卡顿
    汽车轮胎: 马牌和米其林
     */
    public abstract static class Car {
        /**
         * 品牌
         */
        protected String brand;
        /**
         * 音响
         */
        protected String sound;
        /**
         * 轮胎
         */
        protected String tyre;
    }

}
